home *** CD-ROM | disk | FTP | other *** search
/ EnigmA Amiga Run 1996 June / EnigmA AMIGA RUN 08 (1996)(G.R. Edizioni)(IT)[!][issue 1996-06][EARSAN CD VII].iso / earcd / gcc / ixemlsrc.lha / ixemul / library / pipe.c < prev    next >
C/C++ Source or Header  |  1996-03-13  |  13KB  |  515 lines

  1. /*
  2.  *  This file is part of ixemul.library for the Amiga.
  3.  *  Copyright (C) 1991, 1992  Markus M. Wild
  4.  *  Portions Copyright (C) 1994 Rafael W. Luebbert
  5.  *
  6.  *  This library is free software; you can redistribute it and/or
  7.  *  modify it under the terms of the GNU Library General Public
  8.  *  License as published by the Free Software Foundation; either
  9.  *  version 2 of the License, or (at your option) any later version.
  10.  *
  11.  *  This library is distributed in the hope that it will be useful,
  12.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  14.  *  Library General Public License for more details.
  15.  *
  16.  *  You should have received a copy of the GNU Library General Public
  17.  *  License along with this library; if not, write to the Free
  18.  *  Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  19.  *
  20.  *  $Id: pipe.c,v 1.4 1994/06/19 15:14:19 rluebbert Exp $
  21.  *
  22.  *  $Log: pipe.c,v $
  23.  *  Revision 1.4  1994/06/19  15:14:19  rluebbert
  24.  *  *** empty log message ***
  25.  *
  26.  *  Revision 1.2  1992/07/04  19:21:08  mwild
  27.  *  (finally..) fix the bug which could cause pipe readers/writers to deadlock
  28.  *
  29.  * Revision 1.1  1992/05/14  19:55:40  mwild
  30.  * Initial revision
  31.  *
  32.  */
  33.  
  34. #define KERNEL
  35. #include "ixemul.h"
  36. #include "kprintf.h"
  37.  
  38. #include <sys/ioctl.h>
  39. #include <string.h>
  40. #include "select.h"
  41.  
  42. /* information for the temporary implementation of pipes.
  43.    PIPE: has the big disadvantage that it blocks in the most unpleasent
  44.    situations, and doesn't send SIGPIPE to processes that write on
  45.    readerless pipes. Unacceptable for this library ;-)) */
  46.  
  47. #define PIPE_SIZE    5120
  48.  
  49. struct tmp_pipe {
  50.   u_short    tp_flags;        /* see below */
  51.   u_char    tp_buffer[PIPE_SIZE];
  52.   u_char    *tp_reader, *tp_writer;    /* buffer pointers.
  53.                        when tp_reader==tp_writer, no data
  54.                        is available */
  55. };
  56.  
  57. #define TPF_NO_READER    (1<<0)
  58. #define TPF_NO_WRITER    (1<<1)
  59. #define TPF_LOCKED    (1<<2)
  60. #define TPF_WANT_LOCK    (1<<3)
  61.  
  62. static int __pread(), __pwrite(), __pselect(), __pioctl(), __pclose();
  63. static struct tmp_pipe *__pinit();
  64.  
  65. static inline void
  66. __get_pipe (struct file *f)
  67. {
  68.   struct tmp_pipe *tp = f->f_tp;
  69.  
  70. retry:  
  71.   Forbid ();
  72.   for (;;)
  73.     {
  74.       if (!(tp->tp_flags & TPF_LOCKED))
  75.         {
  76.           tp->tp_flags &= ~TPF_WANT_LOCK;
  77.           tp->tp_flags |= TPF_LOCKED;
  78.           /* got it ! */
  79.           break;
  80.     }
  81.       tp->tp_flags |= TPF_WANT_LOCK;
  82.       KPRINTF_DISABLED (("__get_pipe: going to sleep\n"));
  83.       if (ix_sleep ((caddr_t)&tp->tp_flags, "get_pipe") < 0)
  84.         {
  85.       KPRINTF_DISABLED (("__get_pipe: interrupted\n"));
  86.       Permit ();
  87.       setrun (FindTask (0));
  88.           goto retry;
  89.         }
  90.       KPRINTF_DISABLED (("__get_pipe: back from sleep (not interrupted)\n"));
  91.       /* have to always recheck whether we really got the lock */
  92.     }
  93.   Permit ();      
  94. }
  95.  
  96. static inline void
  97. __release_pipe (struct file *f)
  98. {
  99.   struct tmp_pipe *tp = f->f_tp;
  100.  
  101.   Forbid ();
  102.   if (tp->tp_flags & TPF_WANT_LOCK)
  103.     ix_wakeup ((u_int)&tp->tp_flags);
  104.     
  105.   tp->tp_flags &= ~(TPF_WANT_LOCK|TPF_LOCKED);
  106.   Permit ();
  107. }
  108.  
  109.  
  110. int
  111. pipe (int pv[2])
  112. {
  113.   struct file *f1, *f2;
  114.   struct tmp_pipe *tp;
  115.   int res, err, omask;
  116.   
  117.   omask = syscall (SYS_sigsetmask, ~0);
  118.   res = -1; 
  119.   err = EMFILE;
  120.   if ((tp = __pinit ()))
  121.     {
  122.       if (! falloc (&f1, pv))
  123.         {
  124.           if (! falloc (&f2, pv+1))
  125.             {
  126.           f1->f_tp     = tp;
  127.           f1->f_stb.st_mode = 0666 | S_IFCHR;
  128.           f1->f_stb.st_size = PIPE_SIZE;
  129.           f1->f_stb.st_blksize = 512;
  130.           f1->f_flags  = FREAD;
  131.           f1->f_type   = DTYPE_PIPE;
  132.           f1->f_read   = __pread;
  133.           f1->f_write  = 0;
  134.           f1->f_ioctl  = __pioctl;
  135.           f1->f_close  = __pclose;
  136.           f1->f_select = __pselect;
  137.  
  138.           f2->f_tp     = tp;
  139.           f2->f_stb.st_mode = 0666 | S_IFCHR;
  140.           f2->f_stb.st_size = PIPE_SIZE;
  141.           f2->f_stb.st_blksize = 512;
  142.           f2->f_flags  = FWRITE;
  143.           f2->f_type   = DTYPE_PIPE;
  144.           f2->f_read   = 0;
  145.           f2->f_write  = __pwrite;
  146.           f2->f_ioctl  = __pioctl;
  147.           f2->f_close  = __pclose;
  148.           f2->f_select = __pselect;
  149.  
  150.           res = err =0;
  151.           goto ret;
  152.         }
  153.       f1->f_count = 0;
  154.     }
  155.  
  156.       kfree (tp);
  157.     }
  158.  
  159. ret:
  160.   syscall (SYS_sigsetmask, omask);
  161.  
  162.   errno = err;
  163.   KPRINTF_DISABLED (("&errno = %lx, errno = %ld\n", &errno, errno));
  164.   return res;
  165. }
  166.  
  167. static struct tmp_pipe *
  168. __pinit (void)
  169. {
  170.   struct tmp_pipe *tp = (struct tmp_pipe *) kmalloc (sizeof (*tp));
  171.   
  172.   if (tp)
  173.     {
  174.       tp->tp_flags = 0;
  175.       tp->tp_reader = tp->tp_writer = tp->tp_buffer;
  176.     }
  177.  
  178.   return tp;
  179. }
  180.  
  181. static int
  182. __pclose (struct file *f)
  183. {
  184.   ix_lock_base ();
  185.  
  186.   f->f_count--;
  187.  
  188.   if (f->f_count == 0)
  189.     {
  190.       if (f->f_read)
  191.         f->f_tp->tp_flags |= TPF_NO_READER;
  192.       else
  193.     f->f_tp->tp_flags |= TPF_NO_WRITER;
  194.     
  195.       if ((f->f_tp->tp_flags & (TPF_NO_READER|TPF_NO_WRITER)) ==
  196.       (TPF_NO_READER|TPF_NO_WRITER))
  197.     kfree (f->f_tp);
  198.       else
  199.     ix_wakeup ((u_int)f->f_tp);
  200.     }
  201.  
  202.   ix_unlock_base ();
  203.  
  204.   return 0;
  205. }
  206.  
  207. static int
  208. __pread (struct file *f, char *buf, int len)
  209. {
  210.   int omask = syscall (SYS_sigsetmask, ~0);
  211.   int err = errno;
  212.   int really_read = 0;
  213.   struct tmp_pipe *tp = f->f_tp;
  214.  
  215.   __get_pipe (f);
  216.  
  217.   while (len)
  218.     {
  219.       if (tp->tp_reader == tp->tp_writer)
  220.     {
  221.       KPRINTF_DISABLED (("__pread: len == %ld, buffer full\n", len));
  222.       if (tp->tp_flags & TPF_NO_WRITER)
  223.         {
  224.           KPRINTF_DISABLED (("__pread: EOF\n"));
  225.           err = 0;
  226.           break;
  227.         }
  228.     
  229.       if (f->f_flags & FNDELAY)
  230.         {
  231.           if (! really_read)
  232.         {
  233.           really_read = -1;
  234.           err = EAGAIN;
  235.         }
  236.           break;
  237.         }
  238.       else if (really_read)
  239.         {
  240.           err = 0;
  241.           break;
  242.         }
  243.       else
  244.         {
  245.           int sleep_rc;
  246.           KPRINTF_DISABLED (("__pread: going to sleep.\n"));
  247.           /* wait for something to be read or all readers to close */
  248.           Forbid ();
  249.           /* sigh.. Forbid() is necessary, or the other end may change
  250.              the pipe, and in the worst case also settle for sleep(), and
  251.              there it is.. deadlock.. */
  252.           __release_pipe (f);
  253.  
  254.           /* make write interruptible */
  255.           syscall (SYS_sigsetmask, omask);
  256.           sleep_rc = ix_sleep ((caddr_t)tp, "pwrite");
  257.           Permit ();
  258.           if (sleep_rc < 0)
  259.             setrun (FindTask (0));
  260.           omask = syscall (SYS_sigsetmask, ~0);
  261.  
  262.           __get_pipe (f);
  263.           continue;        /* retry */
  264.         }
  265.     }
  266.       else
  267.     {
  268.       /* okay, there's something to read from the pipe */
  269.       if (tp->tp_reader > tp->tp_writer)
  270.         {
  271.           /* read till end of buffer and wrap around */
  272.           int avail = PIPE_SIZE - (tp->tp_reader - tp->tp_buffer);
  273.           int do_read = len < avail ? len : avail;
  274.  
  275.           /* KPRINTF_DISABLED (("__pread-1: reading %ld bytes.\n", do_read)); */
  276.  
  277.           really_read += do_read;
  278.           bcopy (tp->tp_reader, buf, do_read);
  279.           len -= do_read;
  280.           buf += do_read;
  281.           tp->tp_reader += do_read;
  282.           if (tp->tp_reader - tp->tp_buffer == PIPE_SIZE)
  283.         /* wrap around */
  284.         tp->tp_reader = tp->tp_buffer;
  285.         }
  286.       if (len && tp->tp_reader < tp->tp_writer)
  287.         {
  288.           int avail = tp->tp_writer - tp->tp_reader;
  289.           int do_read = len < avail ? len : avail;
  290.  
  291.           /* KPRINTF_DISABLED (("__pread-2: reading %ld bytes.\n", do_read)); */
  292.  
  293.           really_read += do_read;
  294.           bcopy (tp->tp_reader, buf, do_read);
  295.           tp->tp_reader += do_read;
  296.           len -= do_read;
  297.           buf += do_read;
  298.         }
  299.     }
  300.  
  301.       ix_wakeup ((u_int)tp);
  302.     }
  303.  
  304.   __release_pipe (f);
  305.  
  306.   syscall (SYS_sigsetmask, omask);
  307.   errno = err;
  308.   KPRINTF_DISABLED (("&errno = %lx, errno = %ld\n", &errno, errno));
  309.   return really_read;
  310. }
  311.  
  312.  
  313. static int
  314. __pwrite (struct file *f, char *buf, int len)
  315. {
  316.   int  omask = syscall (SYS_sigsetmask, ~0);
  317.   int err = errno;
  318.   int really_written = 0;
  319.   struct tmp_pipe *tp = f->f_tp;
  320.  
  321.   __get_pipe (f);
  322.  
  323.   while (len)
  324.     {
  325.       if (tp->tp_flags & TPF_NO_READER)
  326.     {
  327.       KPRINTF_DISABLED (("__pwrite: SIGPIPE\n"));
  328.       really_written = -1;
  329.       err = EPIPE;
  330.       /* this is something no `real' Amiga pipe handler will do ;-)) */
  331.       _psignal (FindTask (0), SIGPIPE);
  332.       break;
  333.         }
  334.     
  335.       /* buffer full ?? */
  336.       if (tp->tp_reader == tp->tp_writer + 1
  337.       || (tp->tp_reader == tp->tp_buffer 
  338.           && tp->tp_writer == tp->tp_buffer + PIPE_SIZE - 1))
  339.     {
  340.       KPRINTF_DISABLED (("__pwrite: buffer full, len == %ld\n", len));
  341.       if (f->f_flags & FNDELAY)
  342.         {
  343.           if (! really_written)
  344.             {
  345.               really_written = -1;
  346.               err = EAGAIN;
  347.             }
  348.           break;
  349.         }
  350.       else
  351.         {
  352.           int sleep_rc;
  353.           KPRINTF_DISABLED (("__pwrite: going to sleep\n"));
  354.           /* wait for something to be read or all readers to close */
  355.           Forbid ();
  356.           /* sigh.. Forbid() is necessary, or the other end may change
  357.              the pipe, and in the worst case also settle for sleep(), and
  358.              there it is.. deadlock.. */
  359.           __release_pipe (f);
  360.  
  361.           /* make write interruptible */
  362.           syscall (SYS_sigsetmask, omask);
  363.           sleep_rc = ix_sleep ((caddr_t)tp, "pwrite");
  364.           Permit ();
  365.           if (sleep_rc < 0)
  366.             setrun (FindTask (0));
  367.           omask = syscall (SYS_sigsetmask, ~0);
  368.  
  369.           __get_pipe (f);
  370.           continue;        /* retry */
  371.         }
  372.     }
  373.       else
  374.     {
  375.       /* okay, there's some space left to write to the pipe */
  376.  
  377.       if (tp->tp_writer >= tp->tp_reader)
  378.         {
  379.           /* write till end of buffer */
  380.           int avail = PIPE_SIZE - 1 - (tp->tp_writer - tp->tp_buffer);
  381.           int do_write;
  382.  
  383.           if (tp->tp_reader > tp->tp_buffer)
  384.             avail++;
  385.           do_write = len < avail ? len : avail;
  386.  
  387.           /* KPRINTF_DISABLED (("__pwrite-1: writing %ld bytes.\n", do_write)); */
  388.           really_written += do_write;
  389.           bcopy (buf, tp->tp_writer, do_write);
  390.           len -= do_write;
  391.           buf += do_write;
  392.           tp->tp_writer += do_write;
  393.           if (tp->tp_writer - tp->tp_buffer == PIPE_SIZE)
  394.             tp->tp_writer = tp->tp_buffer;
  395.         }
  396.  
  397.       if (tp->tp_writer < tp->tp_reader - 1)
  398.         {
  399.           int avail = tp->tp_reader - tp->tp_writer - 1;
  400.           int do_write = len < avail ? len : avail;
  401.  
  402.           /* KPRINTF_DISABLED (("__pwrite-2: writing %ld bytes.\n", do_write)); */
  403.           really_written += do_write;
  404.           bcopy (buf, tp->tp_writer, do_write);
  405.           tp->tp_writer += do_write;
  406.           len -= do_write;
  407.           buf += do_write;
  408.         }
  409.     }
  410.     
  411.       ix_wakeup ((u_int)tp);
  412.     }
  413.  
  414.   __release_pipe (f);
  415.  
  416.   syscall (SYS_sigsetmask, omask);
  417.   errno = err;
  418.   KPRINTF_DISABLED (("&errno = %lx, errno = %ld\n", &errno, errno));
  419.   return really_written;
  420. }
  421.  
  422. static int
  423. __pselect (struct file *f, int select_cmd, int io_mode)
  424. {
  425.   struct tmp_pipe *tp = f->f_tp;
  426.  
  427.   /* I currently only check whether io is possible, no setup needed.
  428.      This would be quite different if select() waited the given timeout,
  429.      and wouldn't split the timeout into smaller slices */
  430.  
  431.   if (select_cmd == SELCMD_CHECK || select_cmd == SELCMD_POLL)
  432.     {
  433.       /* we support both, read and write checks (hey, something new ;-)) */
  434.       if (io_mode == SELMODE_IN)
  435.     return tp->tp_reader != tp->tp_writer;
  436.  
  437.       else if (io_mode == SELMODE_OUT)
  438.     return !(tp->tp_reader == tp->tp_writer + 1
  439.          || (tp->tp_reader == tp->tp_buffer 
  440.              && tp->tp_writer == tp->tp_buffer + PIPE_SIZE - 1));
  441.     }
  442.  
  443.   return 0;
  444. }
  445.  
  446. static int
  447. __pioctl (struct file *f, unsigned int cmd, unsigned int inout,
  448.           unsigned int arglen, unsigned int arg)
  449. {
  450.   int omask;
  451.   int result = 0;
  452.   struct tmp_pipe *tp = f->f_tp;
  453.   
  454.   omask = syscall (SYS_sigsetmask, ~0);
  455.   __get_pipe (f);
  456.  
  457.   switch (cmd)
  458.     {
  459.     case FIONREAD:
  460.       {
  461.     unsigned int *pt = (unsigned int *)arg;
  462.     if (tp->tp_reader < tp->tp_writer)
  463.       *pt = tp->tp_writer - tp->tp_reader;
  464.     else if (tp->tp_reader > tp->tp_writer)
  465.       *pt = PIPE_SIZE - (tp->tp_reader - tp->tp_writer);
  466.     else
  467.       *pt = 0;
  468.     result = 0;
  469.         break;
  470.       }
  471.  
  472.     case FIONBIO:
  473.       {
  474.     result = f->f_flags & FNDELAY ? 1 : 0;
  475.     if (*(unsigned int *)arg)
  476.       f->f_flags |= FNDELAY;
  477.     else
  478.       f->f_flags &= ~FNDELAY;
  479.     /* I didn't find it documented in a manpage, but I assume, we
  480.      * should return the former state, not just zero.. */
  481.     break;
  482.       }
  483.  
  484.     case FIOASYNC:
  485.       {
  486.     /* DOESN'T WORK YET */
  487.  
  488.     int flags = *(unsigned long*)arg;
  489.     result = f->f_flags & FASYNC ? 1 : 0;
  490.     if (flags)
  491.       f->f_flags |= FASYNC;
  492.     else
  493.       f->f_flags &= ~FASYNC;
  494.  
  495.     /* ATTENTION: have to call some function here in the future !!! */
  496.  
  497.     /* I didn't find it documented in a manpage, but I assume, we
  498.      * should return the former state, not just zero.. */
  499.     break;
  500.       }
  501.  
  502.     case FIOCLEX:
  503.     case FIONCLEX:
  504.     case FIOSETOWN:
  505.     case FIOGETOWN:
  506.       /* this is no error, but nevertheless we don't take any actions.. */      
  507.       result = 0;
  508.       break;
  509.     }
  510.  
  511.   __release_pipe (f);
  512.   syscall (SYS_sigsetmask, omask);
  513.   return result;
  514. }
  515.